#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <errno.h>
#define LISTENQ 1024
#define MAX_ADDRLEN 16

int sig_in_exit = 0;
int sig_num = 0;

void sig_int(int signo){
    sig_num = signo;
    printf("[srv] SIGINT is coming!\n");
    sig_in_exit = 1;
}

void sig_pipe(int signo){
    sig_num = signo;
    printf("[srv] SIGPIPE is coming!\n");
}

void echo_rep(int socket){
    int res, len_h, len_n;
    char *buf;
    do {
        int sum = 0;
        res = read(socket, &len_n, 4);
        if(res < 0){
            printf("[srv] read len return %d and errno is %d\n", res, errno);
            if (errno == EINTR){
                if(sig_num == SIGINT)
                    return;
                continue;
            }
            return;
        }
        if(res == 0)
            return;
        len_h = ntohl(len_n);
        buf = (char *) malloc(len_h);
        while(sum != len_h) {
            res = read(socket, buf + sum, len_h);
            if (res < 0) {
                printf("[srv] read data return %d and errno is %d\n", res, errno);
                if (errno == EINTR){
                    if(sig_num == SIGINT){
                        free(buf);
                        return;
                    }
                    continue;
                }
                return;
            }
            sum += res;
        }
        printf("[echo_rqt] %s\n", buf);
        len_h = strlen(buf) + 1;
        len_n = htonl(len_h);
        res = write(socket, &len_n, 4);
        if(res < 0){
            printf("[srv] write len return %d and errno is %d\n", res, errno);
            if (errno == EINTR)
                continue;
            free(buf);
            return;
        }
        res = write(socket, buf, len_h);
        if (res < 0) {
            printf("[srv] write data return %d and errno is %d\n", res, errno);
            if (errno == EINTR)
                continue;
            free(buf);
            return;
        }
        free(buf);
    }while(1);
}

int main(int argc, char *argv[]) {
    int  connfd;
    struct sigaction sigact_pipe, old_sigact_pipe;

    sigact_pipe.sa_handler = sig_pipe;
    sigemptyset(&sigact_pipe.sa_mask);
    sigact_pipe.sa_flags = 0;
    sigact_pipe.sa_flags |= SA_RESTART;
    sigaction(SIGPIPE, &sigact_pipe, &old_sigact_pipe);

    struct sigaction sigact_int, old_sigact_int;
    sigact_int.sa_handler = sig_int;
    sigemptyset(&sigact_int.sa_mask);
    sigact_int.sa_flags = 0;
    sigaction(SIGINT, &sigact_int, &old_sigact_int);

    struct sockaddr_in srv_addr, cli_addr;
    socklen_t cli_addr_len;
    int listenfd;
    bzero(&srv_addr, sizeof(srv_addr));
    srv_addr.sin_family = AF_INET;
    if (inet_pton(AF_INET, argv[1], &srv_addr.sin_addr.s_addr) <= 0){
        perror("fail to do!\n");
        exit(1);
    }
    srv_addr.sin_port = htons(atoi(argv[2]));
    printf("[srv] server[%s:%s] is initializing!\n", argv[1], argv[2]);
    listenfd = socket(PF_INET, SOCK_STREAM, 0);
    bind(listenfd, (struct sockaddr *)&srv_addr, sizeof(srv_addr));
    listen(listenfd, LISTENQ);
    while (!sig_in_exit){
        cli_addr_len = sizeof(cli_addr);
        connfd = accept(listenfd, (struct sockaddr *)&cli_addr, &cli_addr_len);
        if (connfd == -1 && errno == EINTR && sig_num == SIGINT)
            break;
        if (connfd < 0)
            continue;
    char buf[MAX_ADDRLEN];
    if(inet_ntop(AF_INET, &cli_addr.sin_addr.s_addr, buf, MAX_ADDRLEN) == NULL){
        perror("error!\n");
        exit(1);
    }
        printf("[srv] client[%s:%u] is accepted!\n", buf, ntohs(cli_addr.sin_port));
        echo_rep(connfd);
        close(connfd);
        printf("[srv] connfd is closed!\n");
    }
    close(listenfd);
    printf("[srv] listenfd is closed!\n");
    printf("[srv] server is going to exit!\n");
    return 0;
}